<?php
define('LATENCY',0.015,false);
define('SIGFIG',4,false);
define('TEST_ITTERATIONS',100,false);

class classValues {
	public $int = 11131; // + 5% Mail Spec + 5% Raid Buff <Values Not Added!!!>
	public $spellPower = 17900; // + 10% Raid Buff <Value Not Added!!!>
	public $hit = 5878;
	public $expertise = 0;
	public $hast = 3618;
	public $crit = 1527; // + 5% Raid Buff <Value Not Added!!!>
	public $mastery = 6011; // + 3,000 Raid Buff <Value Added... blame Blizz Char sheet>
	public $dodge = 0;
	public $parry = 0;
	public $passivePercentageBonuses = 0.2;
	public $buffPercentageBonuses = 0.1;
	public $targetDebuffPercentageBonuses = 0.0;
}
class combatRatings {
	function Melee_Hit($value) {
		return ($value / 340)/100;
	}
	function Spell_Hit($value) {
		return ($value / 340)/100;
	}
	function Hast($value) {
		return ($value / 425)/100;
	}
	function Critical_Strike($value) {
		return ($value / 600)/100;
	}
	function Mastery($mastery,$value) {
		switch($mastery) {
			//Shaman
			case 'Elemental_Overload':
				return 0.16 + (($value / 600)/50);
				break;
		}
	}
	function Expertise($value) {
		return ($value / 340)/100;
	}
	function Dodge($value) {
		return ($value / 885)/100;
	}
	function Parry($value) {
		return ($value / 885)/100;
	}
}
class player {
	public $buffs = array(); // SPELL_NAME[Stacks],SPELL_NAME[Duration]
	public $debuffs = array();
	public $castBar = 0; // duration in sec
}
class target {
	public $buffs = array();
	public $debuffs = array(); // SPELL_NAME[Damage],SPELL_NAME[Duration],SPELL_NAME[Ticks]
}
class classSpells {
	//output arrays
	public $coolDown = array(); public $hits = array(); public $crits = array(); public $overloadH = array(); public $overloadC = array();
	//spells
	function Lightning_Bolt($classSpells,$baseValues,$combatRatings,$player,$target) {
		if(!isset($classSpells -> coolDown['Lightning_Bolt'])) {$classSpells -> coolDown['Lightning_Bolt'] = 0;}
		if(!isset($classSpells -> hits['Lightning_Bolt'])) {$classSpells -> hits['Lightning_Bolt'] = array();}
		if(!isset($classSpells -> crits['Lightning_Bolt'])) {$classSpells -> crits['Lightning_Bolt'] = array();}
		if(!isset($classSpells -> overloadH['Lightning_Bolt'])) {$classSpells -> overloadH['Lightning_Bolt'] = array();}
		if(!isset($classSpells -> overloadC['Lightning_Bolt'])) {$classSpells -> overloadC['Lightning_Bolt'] = array();}
		
		$coEfficient = 0.714; $baseDam = rand(1099,1255); $castTime = 2;
		$dam = ($baseDam+$baseValues->spellPower*($coEfficient+$baseValues->passivePercentageBonuses))*(1+$baseValues->buffPercentageBonuses)*(1+$baseValues->targetDebuffPercentageBonuses); //(Base + Spellpower) * Passive Percentage Bonuses * Buff Percentage Bonuses * Target Debuff Percentage Bonuses
		
		//Casting Calcuations
		$player->castBar += math::castTime($castTime);
		
		//Crit Calcs
		$critChance = $combatRatings->Critical_Strike($baseValues->crit); $chance = rand(1,100);
		if($chance <= ($critChance*100)) {
			$crit = math::crit(math::Elemental_Focus($dam,$player));
			$classSpells -> crits['Lightning_Bolt'][] = number_format($crit,SIGFIG,'.',''); //Crit
			//Elemental Focus
			if(!isset($player->buffs['Elemental_Focus'])) {$player->buffs['Elemental_Focus'] = array('Stacks'=>0,'Duration'=>0);}
			$player->buffs['Elemental_Focus']['Stacks'] = 2; $player->buffs['Elemental_Focus']['Duration'] = 30;
		} else {
			$classSpells -> hits['Lightning_Bolt'][] = number_format(math::Elemental_Focus($dam,$player),SIGFIG,'.',''); //Hit
		}
		
		//Overload Calcs
		$overloadChance = $combatRatings->Mastery('Elemental_Overload',$baseValues->mastery); $chance = rand(1,100);
		if($chance <= ($overloadChance*100)) {
			$dam = 0.75 * $dam;
			//Crit Calcs
			$critChance = $combatRatings->Critical_Strike($baseValues->crit); $chance = rand(1,100);
			if($chance <= ($critChance*100)) {
				$crit = math::crit($dam);
				$classSpells -> overloadC['Lightning_Bolt'][] = number_format($crit,SIGFIG,'.',''); //Crit
			} else {
				$classSpells -> overloadH['Lightning_Bolt'][] = number_format($dam,SIGFIG,'.',''); //Hit
			}
		}
	}
	function Lava_Burst($classSpells,$baseValues,$combatRatings,$player,$target) {
		if(!isset($classSpells -> coolDown['Lava_Burst'])) {$classSpells -> coolDown['Lava_Burst'] = 0;}
		if(!isset($classSpells -> hits['Lava_Burst'])) {$classSpells -> hits['Lava_Burst'] = array();}
		if(!isset($classSpells -> crits['Lava_Burst'])) {$classSpells -> crits['Lava_Burst'] = array();}
		if(!isset($classSpells -> overloadH['Lava_Burst'])) {$classSpells -> overloadH['Lava_Burst'] = array();}
		if(!isset($classSpells -> overloadC['Lava_Burst'])) {$classSpells -> overloadC['Lava_Burst'] = array();}
		
		$coEfficient = 1.2; $baseDam = rand(1658,2131); $castTime = 1.5;
		$dam = ($baseDam+$baseValues->spellPower*($coEfficient+$baseValues->passivePercentageBonuses))*(1+$baseValues->buffPercentageBonuses)*(1+$baseValues->targetDebuffPercentageBonuses); //(Base + Spellpower) * Passive Percentage Bonuses * Buff Percentage Bonuses * Target Debuff Percentage Bonuses
		
		//Casting Calcuations
		$player->castBar += math::castTime($castTime);
		
		//Crit Calcs
		$critChance = $combatRatings->Critical_Strike($baseValues->crit); $chance = rand(1,100);
		//Flame Shock Debuff == 100% Crit Chance
		if(isset($target->debuffs['Flame_Shock']['Duration'])) {if($target->debuffs['Flame_Shock']['Duration'] > 0) {$critChance = 1;}}
		
		
		if($chance <= ($critChance*100)) {
			$crit = math::crit(math::Elemental_Focus($dam,$player));
			$classSpells -> crits['Lava_Burst'][] = number_format($crit,SIGFIG,'.',''); //Crit
			//Elemental Focus
			if(!isset($player->buffs['Elemental_Focus'])) {$player->buffs['Elemental_Focus'] = array('Stacks'=>0,'Duration'=>0);}
			$player->buffs['Elemental_Focus']['Stacks'] = 2; $player->buffs['Elemental_Focus']['Duration'] = 30;
		} else {
			$classSpells -> hits['Lava_Burst'][] = number_format(math::Elemental_Focus($dam,$player),SIGFIG,'.',''); //Hit
		}
		//Add spell coolDown
		$classSpells -> coolDown['Lava_Burst'] = 8;
		
		//Overload Calcs
		$overloadChance = $combatRatings->Mastery('Elemental_Overload',$baseValues->mastery); $chance = rand(1,100);
		if($chance <= ($overloadChance*100)) {
			$dam = 0.75 * $dam;
			//Crit Calcs
			$critChance = $combatRatings->Critical_Strike($baseValues->crit); $chance = rand(1,100);
			if($chance <= ($critChance*100)) {
				$crit = math::crit($dam);
				$classSpells -> overloadC['Lava_Burst'][] = number_format($crit,SIGFIG,'.',''); //Crit
			} else {
				$classSpells -> overloadH['Lava_Burst'][] = number_format($dam,SIGFIG,'.',''); //Hit
			}
		}
	}
	function Flame_Shock($classSpells,$baseValues,$combatRatings,$player,$target) {
		if(!isset($classSpells -> coolDown['Flame_Shock'])) {$classSpells -> coolDown['Shock'] = 0;}
		if(!isset($classSpells -> hits['Flame_Shock'])) {$classSpells -> hits['Flame_Shock'] = array();}
		if(!isset($classSpells -> crits['Flame_Shock'])) {$classSpells -> crits['Flame_Shock'] = array();}
		
		$coEfficient = 0.449; $baseDam = 1086; $castTime = 1.5;
		$dam = ($baseDam+$baseValues->spellPower*($coEfficient+$baseValues->passivePercentageBonuses))*(1+$baseValues->buffPercentageBonuses)*(1+$baseValues->targetDebuffPercentageBonuses); //(Base + Spellpower) * Passive Percentage Bonuses * Buff Percentage Bonuses * Target Debuff Percentage Bonuses
		
		//Casting Calcuations
		$player->castBar += math::castTime($castTime);
		
		//Crit Calcs
		$critChance = $combatRatings->Critical_Strike($baseValues->crit); $chance = rand(1,100);
		if($chance <= ($critChance*100)) {
			$crit = math::crit(math::Elemental_Focus($dam,$player));
			$classSpells -> crits['Flame_Shock'][] = number_format($crit,SIGFIG,'.',''); //Crit
			//Elemental Focus
			if(!isset($player->buffs['Elemental_Focus'])) {$player->buffs['Elemental_Focus'] = array('Stacks'=>0,'Duration'=>0);}
			$player->buffs['Elemental_Focus']['Stacks'] = 2; $player->buffs['Elemental_Focus']['Duration'] = 30;
		} else {
			$classSpells -> hits['Flame_Shock'][] = number_format(math::Elemental_Focus($dam,$player),SIGFIG,'.',''); //Hit
		}
		//Add spell coolDown
		$classSpells -> coolDown['Shock'] = 5;
		//Debuff
		if(!isset($target->debuffs['Flame_Shock'])) {$target->debuffs['Flame_Shock'] = array('Damage','Duration','Ticks');}
		$coEfficient = 0.21; $baseDam = 2328;
		$dam = ($baseDam+$baseValues->spellPower*($coEfficient+$baseValues->passivePercentageBonuses))*(1+$baseValues->buffPercentageBonuses)*(1+$baseValues->targetDebuffPercentageBonuses); //(Base + Spellpower) * Passive Percentage Bonuses * Buff Percentage Bonuses * Target Debuff Percentage Bonuses
		$target->debuffs['Flame_Shock']['Damage'] = $dam/12;
		$target->debuffs['Flame_Shock']['Duration'] = 24;
		$target->debuffs['Flame_Shock']['Ticks'] = 12;
	}
}
class math {
	function average($value) {
		if(is_array($value)) {
			$sum = 0; foreach($value as $val) {$sum = $sum + $val;}
			return ($sum === 0 || count($value) === 0?0:number_format(($sum/count($value)),0,'',','));
		}
	}
	function crit($dam) {
		return $dam*(1+(2*1.03-1)*(1+0.5)); //Damage * (1+ ((Base Critical Bonus * Meta Bonus) - 1 ) * (1 + Fury Bonus))
	}
	function Elemental_Focus($dam,$player) {
		if(isset($player->buffs['Elemental_Focus']['Stacks'],$player->buffs['Elemental_Focus']['Duration'])) {
			if($player->buffs['Elemental_Focus']['Stacks'] > 0 && $player->buffs['Elemental_Focus']['Duration'] > 0) {
				$player->buffs['Elemental_Focus']['Stacks'] -= 1;
				return $dam * 1.10;
			}
		}
		return $dam;
	}
	function castTime($spellCastTime) {
		//Needs Hast Calculation!
		return $spellCastTime + LATENCY;
	}
	function minutes($seconds) {
		//return sprintf("%02.2d:%02.2d",floor($seconds/60),$seconds%60);
		return gmdate("H:i:s",$seconds);
	}
}
//Initalise Values
$baseValues = new classValues(); $classSpells = new classSpells(); $combatRatings = new combatRatings(); $player = new player(); $target = new target();

//Test Variables
for($i=0; $i<TEST_ITTERATIONS; $i++) {
	classSpells::Lightning_Bolt($classSpells,$baseValues,$combatRatings,$player,$target);
	classSpells::Lava_Burst($classSpells,$baseValues,$combatRatings,$player,$target);
	classSpells::Flame_Shock($classSpells,$baseValues,$combatRatings,$player,$target);
}
//Results
foreach($classSpells->hits as $spell => $array) {
	if(isset($classSpells->hits[$spell],$classSpells->crits[$spell])) {
		echo '<b>'.$spell.'</b>';
		echo '<br />Num Hits: ' . count($classSpells->hits[$spell]);
		echo '<br />Num Crits: ' . count($classSpells->crits[$spell]);
		echo '<br />Expected Crit Chance = ' . number_format(combatRatings::Critical_Strike($baseValues->crit),SIGFIG,'.','');
		echo '<br />Crit Chance = ' . number_format(count($classSpells->crits[$spell])/(count($classSpells->hits[$spell]) + count($classSpells->crits[$spell])),SIGFIG,'.','');
		echo '<br />Average Hit = ' . math::average($classSpells->hits[$spell]);
		echo '<br />Average Crit = ' . math::average($classSpells->crits[$spell]);
		echo '<br />';
		if(isset($classSpells->overloadH[$spell],$classSpells->overloadC[$spell])) {
			echo '<br />Num Overloads = ' . (count($classSpells->overloadH[$spell]) + count($classSpells->overloadC[$spell]));
			echo '<br />Expected Overload Chance = ' . number_format(combatRatings::Mastery('Elemental_Overload',$baseValues->mastery),SIGFIG,'.','');
			echo '<br />Overload Chance = ' . number_format((count($classSpells->overloadH[$spell]) + count($classSpells->overloadC[$spell]))/count($classSpells->hits[$spell]),SIGFIG,'.','');
			echo '<br />Average Hit = ' . math::average($classSpells->overloadH[$spell]);
			echo '<br />Average Crit = ' . math::average($classSpells->overloadC[$spell]);
			echo '<br /><br />';
		}
	}
}
//Results - Target Debuffs
echo '<br /><b>Target Debuffs</b>';
foreach($target->debuffs as $spell => $array) {
	echo '<br />' . $spell;
}
//Results - Target Debuffs
echo '<br />';
echo '<br /><b>Target Debuff DoT Info</b>';
foreach($target->debuffs as $spell => $array) {
	echo '<br />' . $spell . ': Damage Per Tick = ' . number_format($array['Damage'],SIGFIG,'.','');
	echo '<br />' . $spell . ': Duration = ' . $array['Duration'] . 'sec';
	echo '<br />' . $spell . ': Number of Ticks = ' . $array['Ticks'];
}
//Results - Player Buffs
echo '<br />';
echo '<br /><b>Player Buffs</b>';
foreach($player->buffs as $spell => $array) {
	echo '<br />' . $spell . ': ' . $array['Stacks'];
}
//Results - Player Cast Time
echo '<br />';
echo '<br /><b>Player Cast Time</b>';
echo '<br />Time Spent Casting: ' . $player->castBar . 'sec' . ' ('.math::minutes($player->castBar).')';
?>